﻿// -----------------------------------------------------------------------------
// ABC 是 .NET 5 平台下开发管理的系统。
// Copyright © 2021 ABC,  Co.,Ltd.
//
// 框架：基于 Furion的后台框架：ABC.Admin
// -----------------------------------------------------------------------------

using Furion;

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

using NLog;

using Serilog;
using Serilog.Events;
using Serilog.Sinks.MSSqlServer;

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Unicode;

namespace Tool
{
    /// <summary>
    /// 扩展
    /// </summary>
    public static class AppExtensions
    {

        /// <summary>
        /// Host 主机注入
        /// </summary>
        /// <param name="hostBuilder">Web主机构建器</param>
        /// <returns>IWebHostBuilder</returns>
        public static IHostBuilder InitSerilog(this IHostBuilder hostBuilder)
        {
            hostBuilder.UseSerilogDefault(config =>
            {
                //string LogFilePath(string LogEvent) => $@"{AppContext.BaseDirectory}logs\{LogEvent}\log.log";
                string LogFilePath(string LogEvent) => $@"logs\{LogEvent}\log.txt";
                string SerilogOutputTemplate = "{NewLine}{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message :{Message}{Properties:j}{NewLine}{NewLine} {Exception}" + new string('-', 50);
                config.WriteTo.Console(outputTemplate: SerilogOutputTemplate)
                    .WriteTo.File("logs\\all\\log.txt", rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: true, fileSizeLimitBytes: 20971520, retainedFileCountLimit: 100, shared: true)
                    .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Debug)
                    .WriteTo.File(LogFilePath("Debug"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate, rollOnFileSizeLimit: true, fileSizeLimitBytes: 20971520, shared: true))
                    .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Information)
                    .WriteTo.File(LogFilePath("Information"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate, rollOnFileSizeLimit: true, fileSizeLimitBytes: 20971520, shared: true))
                    .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning)
                    .WriteTo.File(LogFilePath("Warning"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate, rollOnFileSizeLimit: true, fileSizeLimitBytes: 20971520, shared: true))
                    .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error)
                    .WriteTo.File(LogFilePath("Error"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate, rollOnFileSizeLimit: true, fileSizeLimitBytes: 20971520, shared: true))
                    .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Fatal)
                    .WriteTo.File(LogFilePath("Fatal"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate, rollOnFileSizeLimit: true, fileSizeLimitBytes: 20971520, shared: true));
            });
            return hostBuilder;
        }


        /// <summary>
        /// 获取访问信息
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public static string GetVisitInfo(this HttpContext httpContext)
        {
            if (httpContext == null) return "";
            var logcontent = $"访问地址：{httpContext.Request.Path}{httpContext.Request.QueryString}";
            var ipv4 = httpContext.GetRemoteIpAddressToIPv4();
            var ipv6 = httpContext.GetRemoteIpAddressToIPv6();
            logcontent = logcontent.AppendLine($"IPV4:{ipv4}    IPV6:{ipv6}");

            var headers = httpContext.Request.Headers.ToDictionary(x => x.Key, v => v.Value.ToString());
            logcontent = logcontent.AppendLine($"Header：{System.Text.Json.JsonSerializer.Serialize(headers, AppEx.GetDefaultJsonSerializerOptions)}");

            //var area = context.RouteData.Values["area"]?.ToString() ?? "";
            //var controller = context.RouteData.Values["controller"]?.ToString() ?? "";
            //var action = actionContext.RouteData.Values["action"]?.ToString() ?? "";
            // method ：OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法
            try
            {
                if (httpContext.Request.Method.ToLower() != "get")
                {
                    var form = httpContext.Request.Form;
                    logcontent = logcontent.AppendLine($"Form 参数：{System.Text.Json.JsonSerializer.Serialize(form.ToDictionary(x => x.Key, v => v.Value.ToString()), AppEx.GetDefaultJsonSerializerOptions)}");
                }
            }
            catch (Exception ex)
            {
                AppEx.GetLogger(logFloderName: "WebActionFilter").Error(ex.ToStringEx());
            }
            //URL  参数
            if (httpContext.Request.Query.Any())
            {
                var urlpars = httpContext.Request.Query.ToDictionary(x => x.Key, v => v.Value.ToString());
                logcontent = logcontent.AppendLine($"URL 参数：{System.Text.Json.JsonSerializer.Serialize(urlpars, AppEx.GetDefaultJsonSerializerOptions)}");
            }

            return logcontent;
        }

        /// <summary>
        /// 设置通过appsettings 可以下载文件类型 扩展
        /// 此扩展需要在  app.UseStaticFiles() 之前使用
        /// </summary>
        /// <param name="app"></param>
        public static void UseCustomStaticFile(this IApplicationBuilder app)
        {
            var mimes = App.GetConfig<Dictionary<string, string>>("StaticFileOptions:FileExtensionContentType");
            var serveUnknownFileTypes = App.GetConfig<bool>("StaticFileOptions:ServeUnknownFileTypes");
            var physicalFilePath = App.GetConfig<string>("StaticFileOptions:PhysicalFilePath");

            //var a = new PhysicalFileProvider(Directory.GetCurrentDirectory()); ;

            var options = new StaticFileOptions
            {
                //FileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory()),
                //设置不限制content-type 该设置可以下载所有类型的文件，但是不建议这么设置，因为不安全
                //ServeUnknownFileTypes = true
                //下面设置可以下载apk和nupkg类型的文件
                //ContentTypeProvider = new FileExtensionContentTypeProvider(new Dictionary<string, string>
                //{
                //  { ".apk","application/vnd.android.package-archive"},
                //  //{ ".nupkg","application/zip"}
                //})
                ServeUnknownFileTypes = serveUnknownFileTypes,

            };
            if (mimes != null && mimes.Any())
            {
                options.ContentTypeProvider = new FileExtensionContentTypeProvider(mimes);
            }
            if (!string.IsNullOrWhiteSpace(physicalFilePath) && Directory.Exists(physicalFilePath))
            {
                options.FileProvider = new PhysicalFileProvider(physicalFilePath);
            }
            app.UseStaticFiles(options);
            app.UseStaticFiles();//可重复设置，设置后不会异常 

        }
    }
}
